#include"Database.h" 

#include"DatabaseWorker.h"
#include"Settings.h"
#include"Song.h"

#include<stdio.h>

#include<QSet>

Database::Database(QObject *parent):QObject(parent), m_db(QSqlDatabase::addDatabase("QSQLITE")){
	m_addEntryTimer = 0;
	m_worker = 0;
	m_db.setHostName("localhost");
	m_db.setDatabaseName(Settings::instance()->settingsDir() + "sqdp2.db");
	if(!m_db.open()){
		printf("Couldn't open the DB2\n");
		return;
	}
	
	QSqlQuery query("CREATE TABLE IF NOT EXISTS 'song_data' (title TEXT, artist TEXT, album TEXT, trackno INTEGER, path TEXT PRIMARY KEY);", m_db);
	if(query.exec()){
		printf("Query succeeded.\n");
	}else{
		printf("Query failed.\n");
	}
}

Database::~Database(){
	m_db.close();
	printf("~Database()\n");
}


QList<QString> Database::getArtists(){
	QList<QString> ret;
	
	QSqlQuery query("SELECT DISTINCT artist FROM song_data WHERE 1 ORDER BY artist ASC;", m_db);
	if(!query.exec()){
		printf("Error obtaining artists from DB2");
		return ret;
	}
	int pos_artist = query.record().indexOf("artist");
	while(query.next())
		ret.push_back(query.value(pos_artist).toString());
	return ret;
}

QList<QString> Database::getAlbums(const QString &artist){
	QList<QString> ret;
	
	QString queryString("SELECT DISTINCT album FROM song_data WHERE ");
	if(artist.isEmpty())
		queryString.append("1 ORDER BY album ASC;");
	else{
		char artistStr[1024];
		_safeString(artist, artistStr);
		queryString.append("artist = " + QString::fromUtf8(artistStr) + " ORDER BY album ASC;");
	}
	QSqlQuery query(queryString);
	if(!query.exec()){
		printf("Error obtaining albums from DB2\n");
		return ret;
	}
	int pos_album = query.record().indexOf("album");
	while(query.next())
		ret.push_back(query.value(pos_album).toString());
	return ret;
}

QList<QString> Database::getSongs(const QString &artist, const QString &album){
	QList<QString> ret;
	
	QString queryString("SELECT DISTINCT title, path, trackno FROM song_data WHERE ");
	bool first = true;
	if(!artist.isEmpty()){
		first = false;
		char artist_safe[1024];
		_safeString(artist, artist_safe);
		queryString.append("artist = " + QString::fromUtf8(artist_safe) + " ");
	}
	if(!album.isEmpty()){
		if(!first)
			queryString.append("AND ");
		char album_safe[1024];
		_safeString(album, album_safe);
		queryString.append("album = " + QString::fromUtf8(album_safe) + " ");
	}
	queryString.append("ORDER BY trackno ASC;");
	QSqlQuery query(queryString);
	if(!query.exec()){
		printf("Error obtaining albums from DB2\n");
		return ret;
	}
	int pos_title = query.record().indexOf("title");
	int pos_path = query.record().indexOf("path");
	while(query.next()){
// 		printf("Took from db song: %s, %s\n", query.value(pos_title).toString().toUtf8().data(), query.value(pos_path).toString().toUtf8().data());
		ret.push_back( query.value(pos_title).toString() + '\n' + query.value(pos_path).toString() );
	}
	return ret;
}

void Database::reloadSongs(QList<QString> filepaths){
	for(int i = 0; i < filepaths.size(); i++){
		try{
			QPointer<Song> song = new Song(filepaths[i]);
			addEntry(song);
			delete song;
		}catch(SongException e){
			printf("From Database::reloadSongs:\n");
			e.print();
			printf("That's pretty bad...\n");
		}
	}
}

bool Database::addEntry(QPointer<Song> song){
// 	printf("Database::addEntry\n");
	if(!song)
		return false;
	
	if(m_addEntryTimer)
		m_addEntryTimer->stop();
	else{
		m_addEntryTimer = new QTimer(this);
		m_addEntryTimer->setSingleShot(true);
		connect(m_addEntryTimer, SIGNAL(timeout()), this, SLOT(slotAddEntryTimeout()));
	}
	SongData *data = song->data();
	if(data)
		m_pendingSongs.push_back(data);
// 	else
// 		printf("Gotta skip %s\n", song->path().toUtf8().data());
	m_addEntryTimer->start(5000);
// 	printf("Database::addEntry(%s)\n", songData->path.toUtf8().data());
	return true;
}

bool Database::removeEntry(const QString &path){
	char pathString[1024];
	_safeString(path, pathString);
	QSqlQuery query( QString("DELETE FROM song_data WHERE path = ") + pathString );
	return query.exec();
}

void Database::slotAddEntryTimeout(){
	printf("Database::slotAddEntryTimeout\n");
	m_addEntryTimer->disconnect();
	delete m_addEntryTimer;
	m_addEntryTimer = 0;
	
	if(m_worker){
		if(!m_worker->isFinished())
			m_worker->addSongs(m_pendingSongs);
		else{
			delete m_worker;
			m_worker = 0;
		}
	}
	if(!m_worker)
		m_worker = new DatabaseWorker(&m_db, m_pendingSongs, this);
	
	if(!m_worker->isRunning()){
		connect(m_worker, SIGNAL(finished()), this, SLOT(slotWorkerFinished()));
		m_worker->start();
	}
	m_pendingSongs.clear();
	return;
}

void Database::slotWorkerFinished(){
	printf("slotWorkerFinished\n");
	QSet<QString> changedArtists = m_worker->changedArtists();
	printf("Changed Artists:\n");
	for(QSet<QString>::const_iterator it = changedArtists.constBegin(); it != changedArtists.constEnd(); ++it){
		printf("\t%s\n", (*it).toUtf8().data());
	}
	emit contentsChanged(changedArtists);
	delete m_worker;
	m_worker = 0;
	printf("deleted worker\n");
}

void Database::_safeString(const QString &string, char *out){//Preserves special characters...
	if(string.contains('\'') && string.contains('\"')){
		printf("Database::_safeString(%s), can't fix this :|\n", string.toUtf8().data());
		sprintf(out, "NULL");
	}else if(string.contains('\"'))
		sprintf(out, "\'%s\'", string.toUtf8().data());
	else
		sprintf(out, "\"%s\"", string.toUtf8().data());
// 	printf("Database::_safeString(%s)->%s\n", string.toUtf8().data(), out);
}

